function [acq_list, note_list] = datac_notefile(note_file)

% DATAC_NOTEFILE - parse notefiles for stimulus protocols
%
%    [ACQ, NOTE] = DATAC_NOTEFILE(FILE) parses the DATAC note file FILE
%    to obtain the stimulus protocols used to generate the data in a
%    corresponding DATAC file.  Acquisition parameters are stored to a
%    structure array ACQ and text comments are stored to a structure
%    array NOTE.

% By:   S.C. Molitor (smolitor@med.unc.edu)
% Date: August 16, 2000

%
% Small Modification to allow reading of .mat file structure from acq program
% By:   Paul B. Manis (pmanis@med.unc.edu)
% Date: Jan 25, 2001. (see section marked 'PBM Hack' in after argument checking)
% requires 'getprotocol.m', a matlab routine that reads the notes from .mat files.
%

% initialize outputs to prevent MATLAB errors

global DFILE

acq_list = [];
note_list = [];

% validate arguments

if (nargin ~= 1)
    msgbox('Invalid number of arguments', 'DATAC_NOTEFILE Error', 'warn');
    return
elseif (~ischar(note_file) || isempty(note_file))
    msgbox('FILE must be a string', 'DATAC_NOTEFILE Error', 'warn');
    return
end

% PBM Hack to read .mat note files...
[p f e] = fileparts(note_file);

if(strcmp(e, '.mat'))
    [protocol, err] = get_protocol(note_file);
    if(err)
        return;
    else
        [acqlist(1:length(protocol)).time] = deal('');
        % copy protocol structure into acq_list and note_list as best we can.
        for i = 1: length(protocol)
            acq_list(i).time = '';
            acq_list(i).valve = protocol(i).valve;
            acq_list(i).stim_file = protocol(i).proto;
            acq_list(i).macro_file='';
            acq_list(i).macro_arg='';
            acq_list(i).beg_rec = protocol(i).frec;
            acq_list(i).end_rec = protocol(i).lrec;
            acq_list(i).pri_chan = 1;
            acq_list(i).pri_seq = protocol(i).seq;
            acq_list(i).sec_chan = 1;
            acq_list(i).sec_seq = '';
            acq_list(i).sec_cnt = 1;
            acq_list(i).acq_mode = protocol(i).mode;
            acq_list(i).ave_cnt = 1;
            acq_list(i).take_cnt = 1;
            acq_list(i).note = '';
        end;
    end;
    return;
end;
% end of PBM Hack to read .mat information as a notefile.

% global variables

global PRE_1994		% flag to indicate pre-1994 note files
global GLOBAL_PAR		% global acquisition parameters structure

% open file
% exit if not found

fid = fopen(note_file, 'rt');
if (fid == -1)
    QueMessage(sprintf('Note file %s not found on import - faking it', note_file));
    % fake it. Assume might be a neuron or rtxi import
    i = 1;
    acq_list(i).time = '';
    acq_list(i).valve = 1;
    acq_list(i).stim_file = 'hyp_iv';
    acq_list(i).macro_file='';
    acq_list(i).macro_arg='';
    acq_list(i).beg_rec = 1;
    acq_list(i).end_rec = DFILE.records_in_file;
    acq_list(i).pri_chan = 1;
    acq_list(i).pri_seq = sprintf('1;%d', DFILE.records_in_file);
    acq_list(i).sec_chan = 1;
    acq_list(i).sec_seq = '';
    acq_list(i).sec_cnt = 1;
    acq_list(i).acq_mode = 'CC';
    acq_list(i).ave_cnt = 1;
    acq_list(i).take_cnt = 1;
    acq_list(i).note = '';




    return
else
    [line, line_cnt] = next_line(0, fid);
    if (isempty(line))
        msgbox(sprintf('File %s is empty', note_file), 'DATAC_NOTEFILE Error', 'warn');
        return
    end
end

% initialize global parameters structure

field_name = {'time', 'record', 'valve', 'stim_file', 'macro_file', 'macro_args', 'macro_take'};
default_value = {'', 0, 1, '', '', '', 0};
GLOBAL_PAR = defstruc([], field_name, default_value);

% strip token from input line
% obtain record number if token is appropriate type
% obtain time string if token is appropriate type
% exit loop when first record number is found

while (~isempty(line))
    [token, line, line_cnt] = next_token(line, line_cnt, fid);
    if (isempty(token))
        msgbox('Cannot find first record', 'DATAC_NOTEFILE Error', 'warn');
        fclose(fid);
        return
    elseif (get_token_type(token) == 'R')
        GLOBAL_PAR.record = sscanf(token, '[R:%d');
        break
    elseif (get_token_type(token) == 'T')
        GLOBAL_PAR.time = token;
    end
end

% determine whether file is pre-1994 style
% check for invalid first record number
% increment record numbers throughout routine with PRE_1994 flag

if (isempty(GLOBAL_PAR.record))
    msgbox(sprintf('Invalid record number found (line %d)', line_cnt), 'DATAC_NOTEFILE Error', 'warn');
    fclose(fid);
    return
elseif (GLOBAL_PAR.record == 0)
    PRE_1994 = 1;
elseif (GLOBAL_PAR.record == 1)
    PRE_1994 = 0;
else
    msgbox(sprintf('Invalid record number found (line %d)', line_cnt), 'DATAC_NOTEFILE Error', 'warn');
    fclose(fid);
    return
end

% initialize acquisition counter
% counter stores number of acquisitions queued to be written (0, 1 or 2)
% previous acquisition stored in PAR(1) & subsequent ones in PAR(2)
% parameters written when acq_state = 2
% sequence goes input -> PAR(2) -> PAR(1) -> output

acq_state = 0;

% initialize data parameter structure from global parameters
% has two copies for storing parameters on next acquisition
% when previous one hasn't been flushed (acq_state = 2)
% set record number of first acquisition (not set in UPDATE_DATA_PAR)

data_par = update_data_par([], acq_state);
data_par(1).beg_rec = GLOBAL_PAR.record;

% initialize acquisition parameters structure
% has two copies for storing parameters on next acquisition
% when previous one hasn't been flushed (acq_state = 2)

field_name = {'pri_chan', 'pri_seq', 'sec_chan', 'sec_seq', 'seq_cnt', 'acq_mode', 'ave_cnt', 'take_cnt'};
default_value = {0, '', 0, '', 0, '', 0, 0};
acq_par = defstruc([], field_name, default_value);
acq_par(2) = acq_par(1);

% proceed through file in tokenwise fashion
% exit when EOF reached

while (~isempty(line))

    % get next line if line has no commands ('>' or 'MACRO')
    % useful when Vm/Im/Gain/LPF values printed for each record

    while (isempty(find(line, '>')) && isempty(findstr(line, 'MACRO')) && ~isempty(line))
        [line, line_cnt] = next_line(line_cnt, fid);
    end

    % strip token from input line
    % check for empty token

    [token, line, line_cnt] = next_token(line, line_cnt, fid);
    if (isempty(token))
        break
    end

    % execute if token is command, record or time
    % ignore other tokens

    switch (get_token_type(token))

        case 'C'		% token is a command string

            % execute command
            % macro commands don't begin with '>'
            % pre-1994 files require next token ('>> XXX')
            % post-1994 files require end of same token ('>XXX')

            if (strcmp(token, 'MACRO'))
                command_str = lower(token);
            elseif (PRE_1994)
                [token, line, line_cnt] = next_token(line, line_cnt, fid);
                command_str = lower(token);
            else
                command_str = lower(token(2 : end));
            end

            switch (command_str)

                case {'g', 'get'}		% get - get a new stimulus file

                    % reset macro acquisition counter
                    % may be interrupting an acquisition within a macro

                    GLOBAL_PAR.macro_take = 0;

                    % get stim file name

                    [GLOBAL_PAR.stim_file, line, line_cnt] = get_stim_file(line, line_cnt, fid);

                case 'seq'				% seq - execute an acquisition sequence

                    % reset macro acquisition counter
                    % may be interrupting an acquisition within a macro

                    GLOBAL_PAR.macro_take = 0;

                    % update acquisition counter if valid sequence
                    % update next acquisition parameters (input -> PAR(2))

                    [acq_struct, line, line_cnt] = get_acq_par(line, line_cnt, fid);
                    if (isstruct(acq_struct))
                        acq_state = acq_state + 1;
                        acq_par(acq_state) = acq_struct;

                        % find next time & record number tokens
                        % FIND_TOKEN_TYPE will update global record & time variables

                        [token, line, line_cnt] = find_token_type('T', line, line_cnt, fid);
                        [token, line, line_cnt] = find_token_type('R', line, line_cnt, fid);
                    end

                case 'do'				% do - execute sequence stored in a stimulus file

                    % reset macro acquisition counter
                    % may be interrupting an acquisition within a macro

                    GLOBAL_PAR.macro_take = 0;

                    % obtain stimulus file name

                    [GLOBAL_PAR.stim_file, line, line_cnt] = get_stim_file(line, line_cnt, fid);

                    % update acquisition counter if valid sequence
                    % update next acquisition parameters (input -> PAR(2))

                    [acq_struct, line, line_cnt] = get_acq_par(line, line_cnt, fid);
                    if (isstruct(acq_struct))
                        acq_state = acq_state + 1;
                        acq_par(acq_state) = acq_struct;

                        % find next time & record number tokens
                        % FIND_TOKEN_TYPE will update global record & time variables

                        [token, line, line_cnt] = find_token_type('T', line, line_cnt, fid);
                        [token, line, line_cnt] = find_token_type('R', line, line_cnt, fid);
                    end

                case 'macro'		% macro - indicates macro execution

                    % obtain macro name and command line parameters
                    % obtain next line (previous line ended with macro command line)
                    % if macro name starts with 'set', ignore macro

                    % NOTE: this code will fail if a non-acquisition macro
                    %       is executed whose name does not begin with 'set'
                    %
                    %       the worst that will happen is that subsequent acquisitions
                    %       will be incorrectly associated with the macro name
                    %       and consecutive take commands may be grouped together
                    %       as a single acquisition

                    [token, rem] = strtok(line, ' ');
                    [line, line_cnt] = next_line(line_cnt, fid);
                    if (length(token) >= 3)
                        if (strcmp(token(1 : 3), 'set'))
                            token = '';
                            rem = '';
                        end
                    end

                    % reset macro parameters

                    GLOBAL_PAR.macro_file = token;
                    GLOBAL_PAR.macro_args = deblank(rem);
                    GLOBAL_PAR.macro_take = 0;

                case 'return'		% return - indicates end of macro

                    % reset macro parameters

                    GLOBAL_PAR.macro_file = '';
                    GLOBAL_PAR.macro_args = '';
                    GLOBAL_PAR.macro_take = 0;

                case {'take', 'exttake'}	% take/exttake - take specified number of records

                    % increment macro acquisition counter if macro is executing
                    % this is how consecutive TAKE commands within a macro are grouped together!

                    if (~isempty(GLOBAL_PAR.macro_file))
                        GLOBAL_PAR.macro_take = GLOBAL_PAR.macro_take + 1;
                    end

                    % don't add to acquisition list if taking consecutive traces within a macro
                    % this is accomplished by assigning TOKEN a dummy value ('NOT TAKING')

                    if (GLOBAL_PAR.macro_take > 1)
                        token = 'NOT TAKING';
                    else
                        [token, line, line_cnt] = find_token('TAKING', line, line_cnt, fid);
                    end

                    % obtain number of records being taken

                    if (strcmp(token, 'TAKING'))
                        [token, line, line_cnt] = next_token(line, line_cnt, fid);

                        % update acquisition counter if number of records found
                        % reset next acquisition parameters (input -> PAR(2))

                        if (~isempty(token))
                            acq_state = acq_state + 1;
                            acq_par(acq_state) = update_acq_par(acq_par(acq_state), command_str, 1, sscanf(token, '%d'));
                        end
                    end

                case {'ave', 'average'}		% average - average specified number of acquisitions

                    % increment macro acquisition counter if macro is executing
                    % this is how consecutive AVERAGE commands within a macro are grouped together!

                    if (~isempty(GLOBAL_PAR.macro_file))
                        GLOBAL_PAR.macro_take = GLOBAL_PAR.macro_take + 1;
                    end

                    % don't add to acquisition list if taking consecutive traces within a macro
                    % this is accomplished by assigning TOKEN a dummy value ('NOT AVERAGING')

                    if (GLOBAL_PAR.macro_take > 1)
                        token = 'NOT AVERAGING';
                    else
                        [token, line, line_cnt] = find_token('AVERAGING', line, line_cnt, fid);
                    end

                    % obtain number of acquisitions being averaged

                    if (strcmp(token, 'AVERAGING'))
                        [token, line, line_cnt] = next_token(line, line_cnt, fid);

                        % update acquisition counter if number of acquisitions found
                        % reset next acquisition parameters (input -> PAR(2))

                        if (~isempty(token))
                            acq_state = acq_state + 1;
                            acq_par(acq_state) = update_acq_par(acq_par(acq_state), 'average', sscanf(token, '%d'), 1);
                        end
                    end

                case 'until'			% until - take records until timer value reached

                    % reset macro acquisition counter
                    % may be interrupting an acquisition within a macro

                    GLOBAL_PAR.macro_take = 0;

                    % obtain seconds on timer before acquisition is stopped

                    [token, line, line_cnt] = find_token('Until', line, line_cnt, fid);
                    if (strcmp(token, 'Until'))
                        [token, line, line_cnt] = next_token(line, line_cnt, fid);

                        % update acquisition counter if timer limit found
                        % reset next acquisition parameters (input -> PAR(2))
                        % NOTE: store timer limit in TAKE_CNT field of acq_par
                        %       too lazy to create separate field for timer limit

                        if (~isempty(token))
                            acq_state = acq_state + 1;
                            acq_par(acq_state) = update_acq_par(acq_par(acq_state), 'until', 1, sscanf(token, '%d'));
                        end
                    end

                case {'d', 'da', 'dat', 'data'}		% data - take records until stopped

                    % reset macro acquisition counter
                    % may be interrupting an acquisition within a macro

                    GLOBAL_PAR.macro_take = 0;

                    % update acquisition counter
                    % reset next acquisition parameters (input -> PAR(2))

                    acq_state = acq_state + 1;
                    acq_par(acq_state) = update_acq_par(acq_par(acq_state), 'data', 1, 0);

                case {'v0', 'v1', 'v2', 'v3', 'v4'}		% vX - change the valve to X

                    % reset macro acquisition counter
                    % may be interrupting an acquisition within a macro

                    GLOBAL_PAR.macro_take = 0;

                    % obtain valve setting

                    GLOBAL_PAR.valve = sscanf(command_str, 'v%d');

                case 'note'				% note - add text comment

                    % if macro was executing, it's not anymore ....
                    % you wouldn't have a NOTE command in a macro!!!

                    GLOBAL_PAR.macro_file = '';
                    GLOBAL_PAR.macro_args = '';
                    GLOBAL_PAR.macro_take = 0;

                    % obtain token after '>note' command found
                    % will determine how note line is parsed

                    [token, line, line_cnt] = next_token(line, line_cnt, fid);

                    % distinguish between pre-1994 & post-1994 files
                    % post-1994 note files have single & multiline forms

                    if (PRE_1994)

                        % skip time, record number, end bracket & dash
                        % update time or record number if found
                        % store comment to output structure

                        while ((get_token_type(token) == 'T') || (get_token_type(token) == 'R') || ...
                                (token(1) == '-') || (token(1) == ']'))
                            if (get_token_type(token) == 'T')
                                GLOBAL_PAR.time = token;
                            elseif (get_token_type(token) == 'R')
                                GLOBAL_PAR.record = sscanf(token, '[R:%d') + PRE_1994;
                            end
                            [token, line, line_cnt] = next_token(line, line_cnt, fid);
                        end
                        [note_list, line, line_cnt] = store_note(note_list, token, line, line_cnt, fid);

                    elseif (get_token_type(token) == 'C')

                        % skip '>', dash or note time string ('[XX:XX:XX]') token
                        % update time if note time string token is found
                        % store comment to output structure

                        while ((token(1) == '>') || (token(1) == '-') || (get_token_type(token) == 'N'))
                            if (get_token_type(token) == 'N')
                                GLOBAL_PAR.time = token(2 : end - 1);
                            end
                            [token, line, line_cnt] = next_token(line, line_cnt, fid);
                        end
                        [note_list, line, line_cnt] = store_note(note_list, token, line, line_cnt, fid);

                    else
                        [note_list, line, line_cnt] = store_note(note_list, token, line, line_cnt, fid);
                    end

                case {'ac', 'acl', 'aclose'}		% aclose - close acquisition file
                    break

                otherwise				% ignore other commands
            end

            % update acquisition information
            % store parameters after second acquisition has been found (PAR(1) -> output)
            % shift acquisition & sequence information (PAR(2) -> PAR(1))
            % reset acquisition counter

            data_par = update_data_par(data_par, acq_state);
            if (acq_state == 2)
                acq_list = store_acq(acq_list, data_par(1), acq_par(1));
                data_par(1) = data_par(2);
                acq_par(1) = acq_par(2);
                acq_state = 1;
            end

        case 'R'		% update most recent record number
            GLOBAL_PAR.record = sscanf(token, '[R:%d') + PRE_1994;

        case 'T'		% update most recent time string
            GLOBAL_PAR.time = token;

        otherwise
    end

end

% store remaining acquisition information

if (acq_state > 0)
    acq_list = store_acq(acq_list, data_par(1), acq_par(1));
end

% close file
% clear global variables and return

fclose(fid);
clear global GLOBAL_PAR
clear global PRE_1994;
return



% NEXT_TOKEN - get the next token in the file

function [token, new_line, new_cnt] = next_token(old_line, old_cnt, fid)

% initialize outputs

token = '';
new_line = old_line;
new_cnt = old_cnt;

% obtain next token in line
% obtain next line if token or remainder is empty
% check for EOF when obtaining next line

while (isempty(token))
    [token, new_line] = strtok(new_line, ' ');
    if (isempty(deblank(new_line)))
        [new_line, new_cnt] = next_line(new_cnt, fid);
        if (isempty(new_line))
            break
        end
    end
end
return



% NEXT_LINE - get the next line in the file

function [new_line, new_cnt] = next_line(old_cnt, fid)

% initialize outputs

new_line = '';
new_cnt = old_cnt;

% obtain next line if line is empty
% check for EOF when obtaining next line

while (isempty(deblank(new_line)))
    new_line = fgetl(fid);
    if (feof(fid) || isempty(new_line) || (new_line == -1))
        new_line = '';
        return
    else
        new_cnt = new_cnt + 1;
    end
end
return



% FIND_TOKEN - forward search for a specified token

function [token, new_line, new_cnt] = find_token(pattern, old_line, old_cnt, fid)

% initialize outputs

token = '';
new_line = old_line;
new_cnt = old_cnt;

% global variables

global PRE_1994		% flag to indicate pre-1994 note files
global GLOBAL_PAR		% global acquisition parameters structure

% loop through tokens until PATTERN is found
% exit if EOF or empty token or line returned

while (~strcmp(pattern, token) && ~isempty(new_line))

    % if line doesn't have PATTERN, get next line
    % useful when Vm/Im/Gain/LPF values printed for each record

    while (~isempty(new_line))
        if (isempty(findstr(new_line, pattern)))
            [new_line, new_cnt] = next_line(new_cnt, fid);
        else
            break
        end
    end

    % obtain next token

    [token, new_line, new_cnt] = next_token(new_line, new_cnt, fid);
    if (isempty(token))
        break
    end

    % do housekeeping for various tokens found here

    switch (get_token_type(token))

        case 'C'		% command string

            % if command is found, pattern must have been interrupted
            % add command back to line for processing & return nothing

            new_line = [token ' ' new_line];
            token = '';
            break

        case 'R'		% update most recent record number
            GLOBAL_PAR.record = sscanf(token, '[R:%d') + PRE_1994;

        case 'T'		% update most recent time string
            GLOBAL_PAR.time = token;

        otherwise	% unknown type - do nothing
    end
end
return



% FIND_TOKEN_TYPE - forward search for a specified token type

function [token, new_line, new_cnt] = find_token_type(token_type, old_line, old_cnt, fid)

% initialize output

token = '';
new_line = old_line;
new_cnt = old_cnt;

% global variables

global PRE_1994		% flag to indicate pre-1994 note files
global GLOBAL_PAR		% global acquisition parameters structure

% loop through tokens until TYPE is found
% exit if EOF or empty token or line returned
% update record number or time string if found

while ((token_type ~= get_token_type(token)) && ~isempty(new_line))
    [token, new_line, new_cnt] = next_token(new_line, new_cnt, fid);
    if (isempty(token))
        break
    elseif (get_token_type(token) == 'R')
        GLOBAL_PAR.record = sscanf(token, '[R:%d') + PRE_1994;
    elseif (get_token_type(token) == 'T')
        GLOBAL_PAR.time = token;
    end
end
return



% GET_TOKEN_TYPE - find the type of token

function token_type = get_token_type(token)

% initialize output

token_type = 'U';

% check if token is a note line continuation character ('>')

if ((length(token) == 1) && (token(1) == '>'))
    token_type = 'L';
end

% check if token is a command ('>XXX' or '>> XXX')

if (length(token) >= 2)
    if (token(1) == '>')
        token_type = 'C';
    end
end

% check if token is a record ('[R:XXX]')
% check if token is a macro command ('MACRO')

if (length(token) >= 4)
    if (strcmp(token(1 : 3), '[R:') && all(~isletter(token(4 : end - 1))))
        token_type = 'R';
    elseif (strcmp(token, 'MACRO'))
        token_type = 'C';
    end
end

% check if token is a time string ('XX:XX:XX')

if (length(token) == 8)
    if (all(~isletter(token([1 2 4 5 7 8]))) && (token(3) == ':') && (token(6) == ':'))
        token_type = 'T';
    end
end

% check if token is a time string in note ('[XX:XX:XX]')

if (length(token) == 10)
    if (all(~isletter(token([2 3 5 6 8 9]))) && ...
            (token(1) == '[') && (token(4) == ':') && (token(7) == ':') && (token(10) == ']'))
        token_type = 'N';
    end
end
return



% GET_STIM_FILE - obtains the stimulus file name

function [stim_file, new_line, new_cnt] = get_stim_file(old_line, old_cnt, fid)

% initialize outputs

stim_file = '';
new_line = old_line;
new_cnt = old_cnt;

% obtain stimulus file name
% should appear immediately after 'STM:'
% strip path & extension from stimulus filename

[token, new_line, new_cnt] = find_token('STM:', new_line, new_cnt, fid);
if (strcmp(token, 'STM:') && ~isempty(new_line))
    [token, new_line, new_cnt] = next_token(new_line, new_cnt, fid);
    if (~isempty(token))
        [path, stim_file] = fileparts(token);
    end
end
return



% GET_ACQ_PAR - obtain acquisition parameters from stimulus sequence

function [new_par, new_line, new_cnt] = get_acq_par(old_line, old_cnt, fid)

% initialize outputs

new_par = [];
new_line = old_line;
new_cnt = old_cnt;

% global variable

global PRE_1994		% flag to indicate pre-1994 note files

% determine sequence type
% very old ('V'): 'Seq ch: <chan> <seq> <mode> <#acq>' (Pre-1994 only)
% old ('O'): 'SEQ ch: <chan> <seq> <mode> <# acq>'
% primary ('P'):  'PRI SEQ ch: <chan> seq: <seq> ACQ MODE: <mode> <# acq>'
% secondary ('S'):  'PRI SEQ ch: <chan> seq: <seq> SEC SEQ ch: <chan> seq: <seq> ACQ MODE: <mode> <# acq>'
% return w/o parsing if unknown type

% pre-1994 sequence may be on next line
% post-1994 sequence should be on same line

if (PRE_1994)
    [token, new_line, new_cnt] = find_token('Seq', new_line, new_cnt, fid);
    if (strcmp(token, 'Seq'))
        seq_type = 'V';
    else
        return
    end
else
    index = findstr(new_line, 'SEC SEQ');
    if (isempty(index))
        index = findstr(new_line, 'PRI SEQ');
        if (isempty(index))
            index = findstr(new_line, 'SEQ');
            if (isempty(index))
                return
            else
                seq_type = 'O';
            end
        else
            seq_type = 'P';
        end
    else
        seq_type = 'S';
    end
end

% obtain channel number
% skip 'ch:' token

[token, new_line, new_cnt] = find_token('ch:', new_line, new_cnt, fid);
if (strcmp(token, 'ch:'))
    [token, new_line, new_cnt] = next_token(new_line, new_cnt, fid);
    new_par.pri_chan = sscanf(token, '%d');
else
    new_par = [];
    return
end

% obtain sequence string
% skip 'seq:' token for type P/S

if ((seq_type == 'P') || (seq_type == 'S'))
    [token, new_line, new_cnt] = find_token('seq:', new_line, new_cnt, fid);
    if (~strcmp(token, 'seq:'))
        new_par = [];
        return
    end
end
[new_par.pri_seq, new_line, new_cnt] = next_token(new_line, new_cnt, fid);

% obtain secondary channel & sequence for type S
% otherwise clear these values

if (seq_type == 'S')
    [token, new_line, new_cnt] = find_token('ch:', new_line, new_cnt, fid);
    if (strcmp(token, 'ch:'))
        [token, new_line, new_cnt] = next_token(new_line, new_cnt, fid);
        new_par.sec_chan = sscanf(token, '%d');
    else
        new_par = [];
        return
    end
    [token, new_line, new_cnt] = find_token('seq:', new_line, new_cnt, fid);
    if (strcmp(token, 'seq:'))
        [new_par.sec_seq, new_line, new_cnt] = next_token(new_line, new_cnt, fid);
    else
        new_par = [];
        return
    end
else
    new_par.sec_chan = [];
    new_par.sec_seq = '';
end

% calculate expected length of sequence
% include PRI & SEC sequences in calculations

new_par.seq_cnt = length(seqparse(new_par.pri_seq));
if (~isempty(new_par.sec_seq))
    new_par.seq_cnt = new_par.seq_cnt * length(seqparse(new_par.sec_seq));
end

% obtain acquisition mode
% obtain acquisition mode parameter
% skip 'MODE:' token for type P/S

if ((seq_type == 'P') || (seq_type == 'S'))
    [token, new_line, new_cnt] = find_token('MODE:', new_line, new_cnt, fid);
    if (~strcmp(token, 'MODE:'))
        new_par = [];
        return
    end
end
[new_par.acq_mode, new_line, new_cnt] = next_token(new_line, new_cnt, fid);

% convert numeric MODE for type V to 'data' or 'average'

if (seq_type == 'V')
    switch (new_par.acq_mode)
        case '1'
            new_par.acq_mode = 'data';
        case '2'
            new_par.acq_mode = 'average';
        otherwise
            new_par.acq_mode = 'unknown';
    end
end

% store acquisition mode parameter in appropriate location
% parameter location depends on acquisition mode ('data' or 'average')

[token, new_line, new_cnt] = next_token(new_line, new_cnt, fid);
if (strcmp(new_par.acq_mode, 'data'))
    new_par.ave_cnt = 1;
    new_par.take_cnt = sscanf(token, '%d');
elseif (strcmp(new_par.acq_mode, 'average'))
    new_par.ave_cnt = sscanf(token, '%d');
    new_par.take_cnt = 1;
else
    new_par.ave_cnt = 1;
    new_par.take_cnt = sscanf(token, '%d');
end
return



% UPDATE_ACQ_PAR - update acquisition parameters structure

function new_par = update_acq_par(old_par, acq_mode, ave_cnt, take_cnt)

% initialize output

new_par = old_par;

% clear sequence information

new_par.pri_chan = 0;
new_par.pri_seq = '';
new_par.sec_chan = 0;
new_par.sec_seq = '';
new_par.seq_cnt = 0;

% update acquisition mode
% update average count
% update take count

new_par.acq_mode = acq_mode;
new_par.ave_cnt = ave_cnt;
new_par.take_cnt = take_cnt;
return



% UPDATE_DATA_PAR - update data parameters structure

function new_par = update_data_par(old_par, acq_state)

% initialize output

new_par = old_par;

% global variables

global GLOBAL_PAR		% global acquisition parameters structure

% update first record for next acquisition
% update last record for previous acquisition

new_par(1).end_rec = GLOBAL_PAR.record - 1;
new_par(2).beg_rec = GLOBAL_PAR.record;

% update remaining fields for previous acquisition only if none stored

if (acq_state == 0)
    new_par(1).time = GLOBAL_PAR.time;
    new_par(1).valve = GLOBAL_PAR.valve;
    new_par(1).stim_file = GLOBAL_PAR.stim_file;
    new_par(1).macro_file = GLOBAL_PAR.macro_file;
    new_par(1).macro_args = GLOBAL_PAR.macro_args;
end

% update remaining fields for next acquisition

new_par(2).time = GLOBAL_PAR.time;
new_par(2).valve = GLOBAL_PAR.valve;
new_par(2).stim_file = GLOBAL_PAR.stim_file;
new_par(2).macro_file = GLOBAL_PAR.macro_file;
new_par(2).macro_args = GLOBAL_PAR.macro_args;
return



% STORE_ACQ - copy acquisition parameters to output structure

function new_list = store_acq(old_list, data_par, acq_par)

% initialize output & variables

new_list = old_list;

% obtain length of output structure
% add entry if records advanced
% return if ending record decremented (no records acquired)
% overwrite previous if beginning record did not advance (after no records acquired)

list_pos = length(new_list);
if (data_par.beg_rec > data_par.end_rec)
    return
elseif (list_pos == 0)
    list_pos = 1;
elseif (data_par.beg_rec > new_list(list_pos).beg_rec)
    list_pos = list_pos + 1;
elseif (data_par.end_rec < new_list(list_pos).end_rec)
    return
end

% copy data information to output

new_list(list_pos).time = lower(data_par.time);
new_list(list_pos).valve = data_par.valve;
new_list(list_pos).stim_file = lower(data_par.stim_file);
new_list(list_pos).macro_file = lower(data_par.macro_file);
new_list(list_pos).macro_args = lower(data_par.macro_args);
new_list(list_pos).beg_rec = data_par.beg_rec;
new_list(list_pos).end_rec = data_par.end_rec;

% copy acquisition information to output

new_list(list_pos).pri_chan = acq_par.pri_chan;
new_list(list_pos).pri_seq = lower(acq_par.pri_seq);
new_list(list_pos).sec_chan = acq_par.sec_chan;
new_list(list_pos).sec_seq = lower(acq_par.sec_seq);
new_list(list_pos).seq_cnt = acq_par.seq_cnt;
new_list(list_pos).acq_mode = lower(acq_par.acq_mode);
new_list(list_pos).ave_cnt = acq_par.ave_cnt;
new_list(list_pos).take_cnt = acq_par.take_cnt;
return



% STORE_NOTE - copy note file comment to output structure

function [new_list, new_line, new_cnt] = store_note(old_list, token, old_line, old_cnt, fid)

% initialize outputs

new_list = old_list;
new_line = old_line;
new_cnt = old_cnt;

% global variables

global PRE_1994		% flag to indicate pre-1994 note files
global GLOBAL_PAR		% global acquisition parameters structure

% copy time & record number to note structure
% initialize text comment string

new_list(end + 1).time = GLOBAL_PAR.time;
new_list(end).record = GLOBAL_PAR.record;
new_list(end).note = '';

% add tokens to string until known token type or '>' found

while (~isempty(token))
    switch (get_token_type(token))
        case 'C'		% add command back to line
            new_line = [token ' ' new_line];
            break
        case 'T'		% update most recent time
            GLOBAL_PAR.time = token;
            break
        case 'R'		% update most recent record
            GLOBAL_PAR.record = sscanf(token, '[R:%d') + PRE_1994;
            break
        case 'N'		% update most recent time
            GLOBAL_PAR.time = token(2 : end - 1);
            break
        case 'L'		% note line continuation
            new_line = ['>note ' new_line];
            break
        otherwise	% add to note line
            if (isempty(new_list(end).note))
                new_list(end).note = token;
            else
                new_list(end).note = [new_list(end).note ' ' token];
            end
            [token, new_line, new_cnt] = next_token(new_line, new_cnt, fid);
    end
end
return
